<?php
/**
 * CreateUser: zlh
 * CreateTime: 2022/1/29 12:40
 * Remark:
 */

namespace App\Http\Controllers\Login;

use App\Consts\RedisConsts\RedisConsts;
use App\Consts\ResponseConsts\ResponseStatusConsts;
use App\Func\EncryptionFunc;
use App\Func\ResponseFunc;
use App\Func\TokenFuc;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Staff\StaffController;
use App\Http\Requests\ListBasicRequest;
use App\Http\Requests\Login\LoginLoginPost;
use App\Models\Log\LoginLog;
use App\Models\Staff\StaffModel;
use App\Service\Company\CompanyService;
use App\Service\Login\LoginService;
use App\Service\Staff\StaffService;
use App\Tools\DingTalk\DingTalkDeptUserFacade;
use App\Tools\Token\LoginToken;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
use Ip2Region;
use JetBrains\PhpStorm\NoReturn;
use Lcobucci\JWT\Token;

class LoginController extends Controller
{
    private LoginService $_loginService;
    private CompanyService $_companyService;
    private StaffService $_staffService;

    public function __construct()
    {
        $this->middleware([
            'loginLeg'
        ]);
        $this->_loginService = new LoginService();
        $this->_companyService = new CompanyService();
        $this->_staffService = new StaffService();
    }

    private function InsertLoginLog($staffId){
        $ip = request()->ip();
        $ip2region = new Ip2Region();
        $info = $ip2region->btreeSearch($ip);
        $region = explode("|",$info['region']);
        $str = "";
        foreach($region as $value){
            if($value){
                $str .= $value;
            }
        }
        $loginLogModel = new LoginLog();
        $loginLogModel->add([
            'staff_id' => $staffId,
            'login_ip' => $ip,
            'login_location' => $str ?? ""
        ]);
    }

	/* 单点登录 by breezeer @2022.08.10
	 *
	 *
	 *
	 */
	private function attachSinglePermissionVerify($n_staff_user_id,$tokenID)
	{
		app()->gcProviderVerifyUserVisitPermission->setUserVisitPermission($n_staff_user_id,$tokenID);
	}
 

    /**
     * 登录
     * @param LoginLoginPost $request
     */
    public function Login(LoginLoginPost $request): \Illuminate\Http\JsonResponse
    {
        // 密码校验通过后生成 当前用户所属的公司部门职位
        $this->_loginService->getStaffDepartments($request['staffId']);
        // 获取用户是否是第一次登陆
        $isLogged = $this->_staffService->getStaffDetailCustom($request['staffId'],["is_logged"]);
        // 生成一个登录后校验Token
//        $token = $request['staffId']."_".md5($request['staffId'])."_".md5("22030302").md5("347722214");
        $lt = new LoginToken();
        $token = $lt->setToken($request['staffId']);
        Redis::setex($token,RedisConsts::REDIS_LOGIN_TOKEN_CONSTS,$request['staffId']);
        // 记录真实的 requestId
        $requestId =
            md5(EncryptionFunc::encryptionHash(time()+rand(100,500))). "-".
            md5(EncryptionFunc::encryptionHash(time()+rand(500,1000)))."-".
            md5(EncryptionFunc::encryptionHash(time()+rand(500,1000)));
        Redis::setex($requestId,RedisConsts::REDIS_TOKEN_CONSTS,1);
        // 生成单点登陆唯一校验token
        $tokenV2 = md5(app()->gcHelper->gfCreateUUID());
        
        # by breezeer @2022.08.09 => 单点登录
		#
		$this->attachSinglePermissionVerify($request['staffId'],$tokenV2);

		// 登录成功记录IP
        $this->InsertLoginLog($request['staffId']);
        // 更新用户最后登录时间
        $staffModel = new StaffModel();
        $staffModel->editStaffBasic($request['staffId'],[
            'staff_last_login_time' => date("Y-m-d h:i:s",time())
        ]);
        return ResponseFunc::returnJson(
            'ok',
            [
                'token' => $token,
                'request_id' => $requestId,
                'request_id_v2' => $tokenV2,
                'request_id_v3' => 0,
                'isFirst' => !!!$isLogged->is_logged
            ],
            "登录成功",
            ResponseStatusConsts::OK_200_RESPONSE_STATUS
        );
    }

    public function logout(){
        $staffId = TokenFuc::getCurrentStaffInfo()['staff_id'];
        $lt = new LoginToken();
        $staffToken = $lt->setToken($staffId);
        $deptToken = $lt->setDeptToken($staffId);
        Redis::del($staffToken);
        Redis::del($deptToken);
        return ResponseFunc::returnJson(
            'ok',
            [],
            "退出登录成功",
            ResponseStatusConsts::OK_200_RESPONSE_STATUS
        );
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function loginDepartment(Request $request): \Illuminate\Http\JsonResponse
    {
        // 查询用户的职位部门
        return ResponseFunc::returnJson(
            'ok',
            $this->_loginService->loginDepartment($request['staffInfo']),
            "获取当前用户登录部门成功",
            ResponseStatusConsts::OK_200_RESPONSE_STATUS
        );
    }

    /**
     * 获取公司下拉用于登录
     * @return \Illuminate\Http\JsonResponse
     */
    public function getCompanySelectByLogin(): \Illuminate\Http\JsonResponse
    {
        return ResponseFunc::returnJson(
            'ok',
            $this->_companyService->getCompanySelectByLogin(),
            '获取公司下拉成功',
            ResponseStatusConsts::OK_200_RESPONSE_STATUS
        );
    }

    /**
     * 钉钉扫码登录
     */
    #[NoReturn] public function dingTalkScanQRCodesLogin(){
        $data = request()->all();
        // 生成单点登陆唯一校验token
        $tokenV2 = md5(app()->gcHelper->gfCreateUUID());
        $tokenV3 = '';
        if(isset($data['p'])){
            $staffController = new StaffController();
            $staffController->bindDingTalk($tokenV2);
        }
        $code = $data['code'];
        $ivT = $data['t'];
        $u = $data['u'];
        $urlIv = EncryptionFunc::getOpensslIv(2,$ivT);
        $decryBindUrl = EncryptionFunc::decryptOpenssl($u,$urlIv);
        $unionId = DingTalkDeptUserFacade::getDingTalkScanOrCodes($code);
        $dingTalkUserId = DingTalkDeptUserFacade::getDingTalkUserIdByUnionId($unionId);
        $userInfo = $this->_staffService->getStaffDetailByDingTalkId($dingTalkUserId);
        $staffId = $userInfo['staff_id'] ?? 0;
        if(!$staffId){
            $returnUrl = $decryBindUrl."?auto=false&ok=false&msg=当前用户未绑定账号&t=''&rid=''";
            header("Location: $returnUrl");
            die();
        }
        // 通过钉钉ID查询 userId
        $lt = new LoginToken();
        $token = $lt->setToken($staffId);
        Redis::setex($token,RedisConsts::REDIS_LOGIN_TOKEN_CONSTS,$staffId);
        // 记录真实的 requestId
        $requestId = md5(EncryptionFunc::encryptionHash(time()+rand(100,500)))."-".md5(EncryptionFunc::encryptionHash(time()+rand(500,1000)))."-". md5(EncryptionFunc::encryptionHash(time()+rand(500,1000)));
        Redis::setex($requestId,RedisConsts::REDIS_TOKEN_CONSTS,1);

		# by breezeer @2022.08.09 => 单点登录
		#
		$this->attachSinglePermissionVerify($staffId,$tokenV2);
        
        $returnUrl = $decryBindUrl."?auto=true&ok=true&msg=登录成功&t=$token&rid=$requestId&v2=$tokenV2&v3=$tokenV3";
        header("Location: $returnUrl");
    }

    /**
     * 获取自己的登录日志
     * @return \Illuminate\Http\JsonResponse
     */
    public function loginStaffLog(ListBasicRequest $request): \Illuminate\Http\JsonResponse
    {
        $filters = $request->get('filters');
        $pageSize = $request->get('page_size');
        $staff = TokenFuc::getCurrentStaffInfo();
        $lm = new LoginLog();
        return ResponseFunc::returnJson(
            'ok',
            $lm->getStaffLoginLog($staff['staff_id'],$filters,$pageSize),
            '获取登录日志成功',
            ResponseStatusConsts::OK_200_RESPONSE_STATUS
        );
    }

    //获取用户IP地址
    public function getIp()
    {
        if(!empty($_SERVER["HTTP_CLIENT_IP"]))
        {
            $cip = $_SERVER["HTTP_CLIENT_IP"];
        }
        else if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]))
        {
            $cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        }
        else if(!empty($_SERVER["REMOTE_ADDR"]))
        {
            $cip = $_SERVER["REMOTE_ADDR"];
        }
        else
        {
            $cip = '';
        }
        preg_match("/[\d\.]{7,15}/", $cip, $cips);
        $cip = isset($cips[0]) ? $cips[0] : 'unknown';
        unset($cips);
        return $cip;
    }

}
